#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include "device_auth.h"

#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "device_auth.h"
#include "securec.h"

#define PORT 10001
#define LOGI printf
#define TEST_APP_NAME "com.huawei.security"
#define MAX_BUF 1000

static int clientfd = -1;
int g_finishBind = 0;
char g_hostUdid[MAX_BUF] = "ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00";
char g_sip[MAX_BUF] = {0};

static bool OnTransmitNet(int64_t requestId, const uint8_t *data, uint32_t dataLen)
{
    int32_t cnt;
    LOGI("------------------OnTransmit------------------\r\n");
    LOGI("|  RequestId: %-30lld  |\r\n", requestId);
    LOGI("|  SendData: %s  |", (char *)data);
    LOGI("------------------OnTransmit------------------\r\n");
    LOGI("Transmit:%s\r\n", data);
    cnt = send(clientfd, (const char *)data, dataLen, 0);
    LOGI("send size %d, process size %d\r\n", dataLen, cnt);
    return true;
}

static void OnSessionKeyReturned(int64_t requestId, const uint8_t *sessionKey, uint32_t sessionKeyLen)
{
    LOGI("------------------OnSessionKeyReturned------------------\r\n");
    LOGI("|  RequestId: %-40lld  |\r\n", requestId);
    LOGI("|  SessionKeyLen: %-36d  |\r\n", sessionKeyLen);
    LOGI("------------------OnSessionKeyReturned------------------\r\n");
}

static void OnFinish(int64_t requestId, int operationCode, const char *authReturn)
{
    LOGI("------------------OnFinish------------------\r\n");
    LOGI("|  RequestId: %-27lld  |\r\n", requestId);
    LOGI("|  OperationCode: %-23d  |\r\n", operationCode);
    LOGI("|  ReturnData: %-26s  |\r\n", authReturn);
    LOGI("------------------OnFinish------------------\r\n");
    if (operationCode == 1 || operationCode == 0 ) {
        return;
    }
    close(clientfd);
    g_finishBind = 1;
}

static void OnError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn)
{
    LOGI("-------------------OnError------------------\r\n");
    LOGI("|  RequestId: %-27lld  |\r\n", requestId);
    LOGI("|  OperationCode: %-23d  |\r\n", operationCode);
    LOGI("|  ErrorCode: %-27d  |\r\n", errorCode);
    LOGI("-------------------OnError------------------\r\n");
}

static char *OnBindRequestController(int64_t requestId, int operationCode, const char *reqParams)
{
    LOGI("------------------OnRequest------------------\r\n");
    LOGI("|  RequestId: %-29lld  |\r\n", requestId);
    LOGI("|  OperationCode: %-25d  |\r\n", operationCode);
    LOGI("|  reqParams: %s  |\r\n", (char *)reqParams);
    LOGI("------------------OnRequest------------------\r\n");
    char *buf = calloc(1, MAX_BUF);
    static char request[] = "{\"confirmation\":0x80000006,\"pinCode\":\"000000\",\"deviceId\":\"ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00\"}";
    strcpy_s(buf, MAX_BUF, request);
    return buf;

}

static const DeviceGroupManager *registerCallbackController(DeviceAuthCallback *callback)
{
    callback->onRequest = OnBindRequestController;
    callback->onError = OnError;
    callback->onFinish = OnFinish;
    callback->onSessionKeyReturned = OnSessionKeyReturned;
    callback->onTransmit = OnTransmitNet;
    const DeviceGroupManager *gm = GetGmInstance();
    gm->regCallback(TEST_APP_NAME, callback);
    return gm;
}


void onGroupCreated(const char *groupInfo)
{
    if (groupInfo == NULL) {
        LOGI("not expected");
        return;
    }
    LOGI("%s\n", groupInfo);
}
void onGroupDeleted(const char *groupInfo)
{
    if (groupInfo == NULL) {
        LOGI("not expected");
        return;
    }
    LOGI("%s\n", groupInfo);
}


DataChangeListener listenerCtx = { NULL };
const DeviceGroupManager *g_gmInst = NULL;

static int CreateGroup3516()
{
    const char *createParamsFmt = "{\"groupType\":256,\"deviceId\":\"%s\",\"userType\":0,\""
                                   "groupVisibility\":-1,\"expireTime\":90,\"groupName\":\"P2PGroup\"}";
    char createParamsBuff[1024] = {0};
    (void)sprintf(createParamsBuff, createParamsFmt, g_hostUdid);
    return g_gmInst->createGroup(ANY_OS_ACCOUNT, 0, TEST_APP_NAME, createParamsBuff);
}

static int AddMember3516()
{
    static char para[] = "{\"groupId\":\"FF9B5A053D74CC8835DB98FAADBCE1A8E4C441637A3A170CB95D4DDD83319C49\",\"groupType\":256,\"pinCode\":\"000000\",\"isAdmin\":true}";
    int ret = g_gmInst->addMemberToGroup(ANY_OS_ACCOUNT, 1234567890000000, TEST_APP_NAME, para);
    return ret;
}

int OpenClientSocket(const char *peerIp, int port)
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        LOGI("%d:fd=%d", __LINE__, fd);
        return -1;
    }
    struct sockaddr_in addr;
    if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != EOK) {
        LOGI( "memset failed");
    }
    addr.sin_family = AF_INET;
    inet_pton(AF_INET, peerIp, &addr.sin_addr);
    addr.sin_port = htons(port);
    int rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
    if (rc == -1) {
        LOGI("fd=%d,connect rc=%d", fd, rc);
        return -1;
    }
    return fd;
}

void TestController3516InClient()
{
    int ret;
    char buf[2048] = {0};
    int count;

    ret = CreateGroup3516();
    if (ret != 0) {
        LOGI("create group failed %d\r\n", ret);
    }
   
    clientfd = OpenClientSocket(g_sip, PORT);
    if (clientfd < 0) {
        LOGI("open sokect fail %d\r\n", clientfd);
        return;
    }

    ret = AddMember3516();
    if (ret != 0) {
        LOGI("AddMember3516 fail %d\r\n", ret);
    }

    while (1) {
        if (g_finishBind) {
            LOGI("bind finish quit...\r\n");
            break;
        }
        memset(buf, 0, sizeof(buf));
        count = recv(clientfd, buf, sizeof(buf), 0);
        if (count < 0) {
            LOGI("recv fail");
            return;
        }
        if (count > 0) {
            LOGI("recv len %d\r\n", count);
            LOGI("recv data :%s\r\n", buf);
            g_gmInst->processData(1234567890000000, (uint8_t *)buf, (uint32_t)(count));
        }
        sleep(1);
    }
}

void devauth_test_bind()
{
    InitDeviceAuthService();
    DeviceAuthCallback callback;
    g_gmInst = registerCallbackController(&callback);
    if (g_gmInst == NULL) {
        LOGI("init module instance failed\r\n");
        return;
    }

    listenerCtx.onGroupCreated = onGroupCreated;
    listenerCtx.onGroupDeleted = onGroupDeleted;
    g_gmInst->regDataChangeListener(TEST_APP_NAME, &listenerCtx);
    TestController3516InClient();
}

int main(int argc, char **argv)
{
    LOGI("client binding\n del /data/data/deviceauth/hcgroup.dat bind before\n");
    if (argc != 2 || argv[1] == 0) {
        LOGI("ip  is null\n");
        return 0;
    }
    strcpy_s(g_sip, sizeof(g_sip), argv[1]);
    LOGI("bind peer ip %s\n", g_sip);
    devauth_test_bind();
    LOGI("client bind ok\n");
    return 0;
}
